
#include "pm_device.h"
#include "pm_regulator.h"
#include "pm_dvfs.h"
#include "pm_avs.h"
#include "pm_avs.h"

#include "pm_dev_api.h"

#ifdef PM_DOMAIN_CORE_ON
#include "pm_core_avs.h"
#include "pm_core.h"
#endif


#ifdef PM_DOMAIN_MEDIA_ON
#include "hal_media_frq.h"
#include "pm_media_avs.h"
#include "pm_media.h"
#endif

#ifdef PM_DOMAIN_CPU_ON
#include "pm_cpu_freq.h"
#include "pm_cpu.h"
#endif

#include "pm_ext.h"


#define SUM_PIXEL_4K_30 (3840*2160*30)
#define SUM_PIXEL_4K_15 (3840*2160*15)

static hi_media_freq s_media_freq;
static hi_u32 s_old_profile = 3;
static hi_bool s_bset_media_freq_done = HI_FALSE;
static hi_mpi_pm_media_cfg g_pm_usrcfg = {};
extern struct pm_device g_pm_dev;


/*
 *  dvfs_ctrl:cpu domain dvfs ctrl interface
 *  parameter:0:disable dvfs;  others:enable dvfs
 *  return:-1:fail;   0:ok
 */
int dvfs_ctrl(int enable)
{
    if (g_pm_dev.domain_num == 0) {
        osal_printk("error: no domain register!\n");
        return -1;
    }
    osal_mutex_lock(&(g_pm_dev.cpu_domain_device->freq_dev->lock));
    if (enable) {
        g_pm_dev.cpu_domain_device->freq_dev->dvfs_enable = 1;
    } else {
        g_pm_dev.cpu_domain_device->freq_dev->dvfs_enable = 0;
    }
    osal_mutex_unlock(&(g_pm_dev.cpu_domain_device->freq_dev->lock));
    return 0;
}

/*
 *  svp_ctrl:samrt version proc ctrl interface
 *  parameter:0:disable svp;  others:enable svp
 *  return:-1:fail;   0:ok
 */
int svp_ctrl(int enable)
{
    hi_pm_misc_policy misc_policy = (hi_pm_misc_policy)pm_hal_get_misc_policy();
    if (misc_policy  == HI_PM_MISC_POLICY_NONE || misc_policy  == HI_PM_MISC_POLICY_BUTT) {
        osal_printk("  no misc policy used !.\n");
        return 0;
    }
    osal_printk("  svp_ctrl :%d ok!\n", enable);
    return 0;
}

/*
 *  pm_ctrl:power manager ctrl interface
 *  parameter:0:disable pm;  others:enable pm
 *  return:-1:fail;   0:ok
 */
int pm_ctrl(int enable)
{
    if (g_pm_dev.domain_num == 0) {
        osal_printk("error: no domain register!\n");
        return -1;
    }
    osal_mutex_lock(&(g_pm_dev.lock));
    if (enable) {
        g_pm_dev.pm_enable = 1;
    } else {
        g_pm_dev.pm_enable = 0;
    }
    osal_mutex_unlock(&(g_pm_dev.lock));
    return 0;
}


#ifdef PM_DOMAIN_CPU_ON

#ifdef __LITEOS__


/*
 * get_cpu_max_profile: get cpu domain max profile index
 * return:max profile index value
 */
int get_cpu_max_profile(void)
{
    if (g_pm_dev.domain_num == 0) {
        osal_printk("error: no domain register!\n");
        return -1;
    }
    return g_pm_dev.cpu_domain_device->freq_dev->profile_num - 1;
}

/*
 * get_cpu_profile: get cpu domain profile index
 * return:profile index value
 */
int get_cpu_profile(void)
{
    if (g_pm_dev.domain_num == 0) {
        osal_printk("error: no domain register!\n");
        return -1;
    }
    return cpu_domain_getprofile();
}

/*
 * set_cpu_profile: set cpu domain profile index
 * parameter:profile index
 * return:0:ok;   -1:fail
 */
int set_cpu_profile(int profile)
{
    if (g_pm_dev.domain_num == 0) {
        osal_printk("error: no domain register!\n");
        return -1;
    }
    int max_profile = g_pm_dev.cpu_domain_device->freq_dev->profile_num - 1;
    if (g_pm_dev.pm_enable) {
        osal_printk("ERROR:please disable pm!\n");
        return -1;
    }
    if (profile < 0 || profile > max_profile) {
        osal_printk("ERROR: set_profile=%0d must be:[0~%0d]\n", profile, max_profile);
        return -1;
    }
    cpu_domain_setprofile(profile);
    return 0;
}
#endif

#endif


#ifdef PM_DOMAIN_MEDIA_ON

/*
 * get_media_max_profile: get media domain max profile index
 * return:max profile index value
 */
int get_media_max_profile(void)
{
    if (g_pm_dev.domain_num == 0) {
        osal_printk("error: no domain register!\n");
        return -1;
    }
    return 3;
}

/*
 * get_media_profile: get media domain profile index
 * return:profile index value
 */
int get_media_profile(void)
{
    if (g_pm_dev.domain_num == 0) {
        osal_printk("error: no domain register!\n");
        return -1;
    }
    int profile = media_domain_getprofile();
#if 0
    switch (profile) {
#ifdef HI3559
        case 0:
            profile = 2;
            break;
        case 1:
            profile = 3;
            break;
#endif
#ifdef HI3556
        case 0:
            profile = 1;
            break;
        case 1:
            profile = 2;
            break;
        case 2:
            profile = 3;
            break;
#endif
        default:
            profile = -1;
            osal_printk("ERROR: profile[%0d] is invalid!\n", profile);
    }
#endif
    return profile;
}

/*
 * set_media_profile: set media domain profile index
 * parameter:profile index
 * return:0:ok;   -1:fail
 */
int set_media_profile(int profile)
{
    if (g_pm_dev.domain_num == 0) {
        osal_printk("error: no domain register!\n");
        return -1;
    }
    if (g_pm_dev.pm_enable) {
        osal_printk("ERROR:please disable pm!\n");
        return -1;
    }
    media_domain_setprofile(profile);
    return 0;
}


hi_s32 set_media_profile_by_media_freq(hi_media_freq *media_freq)
{
    hi_u32 profile = 0;
    hi_s32 ret = HI_SUCCESS;
    pm_hal_get_media_profile(media_freq, &profile);
    s_old_profile = get_media_profile();
    if (profile == s_old_profile) {
        set_media_freq_reg(media_freq);
        memcpy(&s_media_freq, media_freq, sizeof(hi_media_freq));
        s_bset_media_freq_done = HI_TRUE;
    } else if (profile > s_old_profile) { /** boosted voltage first ,then increase of frequency*/
        pm_ctrl(0);
        ret = set_media_profile(profile);
        if (ret != HI_SUCCESS) {
            osal_printk("set media profile %d error:%d.\n", profile, ret);
            pm_ctrl(1);
            return HI_FAILURE;
        }
        pm_ctrl(1);
        set_media_freq_reg(media_freq);
        memcpy(&s_media_freq, media_freq, sizeof(hi_media_freq));
        s_bset_media_freq_done = HI_TRUE;
    } else { /**  reduce the frequency first, then reduction voltage */
        set_media_freq_reg(media_freq);
        memcpy(&s_media_freq, media_freq, sizeof(hi_media_freq));
        s_bset_media_freq_done = HI_TRUE;
        pm_ctrl(0);
        ret = set_media_profile(profile);
        if (ret != HI_SUCCESS) {
            osal_printk("set media profile %d error:%d.\n", profile, ret);
            pm_ctrl(1);
            return HI_FAILURE;
        }
        pm_ctrl(1);
    }
    s_old_profile = profile;
    return HI_SUCCESS;
}



int get_media_usrcfg(hi_mpi_pm_media_cfg *pmedia_usrcfg)
{
    hi_media_avs_policy media_avs_policy = (hi_media_avs_policy)hal_media_get_avs_policy();
    if (HI_MEDIA_AVS_POLICY_HPM  != media_avs_policy) {
        return 0;
    }
    if (pmedia_usrcfg == NULL) {
        osal_printk("error: pmedia_usrcfgr is null!\n");
        return -1;
    }
    osal_memcpy(pmedia_usrcfg, &g_pm_usrcfg, sizeof(hi_mpi_pm_media_cfg));
    return HI_SUCCESS;
}

int set_media_usrcfg(hi_mpi_pm_media_cfg *pmedia_usrcfg)
{
    if (pmedia_usrcfg == NULL) {
        osal_printk("error: pmedia_usrcfgr is null!\n");
        return -1;
    }
    osal_memcpy(&g_pm_usrcfg, pmedia_usrcfg, sizeof(hi_mpi_pm_media_cfg));
    return HI_SUCCESS;
}

hi_s32 set_media_profile_by_usr_cfg(hi_mpi_pm_media_cfg *usr_param)
{
    hi_u32 profile = 0;
    hi_s32 ret = HI_SUCCESS;
    hi_media_freq media_freq = {};
    hi_media_avs_policy media_avs_policy = (hi_media_avs_policy)hal_media_get_avs_policy();
    if (HI_MEDIA_AVS_POLICY_HPM  != media_avs_policy) {
        return 0;
    }
    pm_hal_get_media_freq_by_usr_cfg(usr_param, &media_freq);
    pm_hal_get_media_profile(&media_freq, &profile);
    s_old_profile = get_media_profile();
    if (profile == s_old_profile) {
        set_media_freq_reg(&media_freq);
        memcpy(&s_media_freq, &media_freq, sizeof(hi_media_freq));
        s_bset_media_freq_done = HI_TRUE;
    } else if (profile > s_old_profile) { /** boosted voltage first ,then increase of frequency*/
        pm_ctrl(0);
        ret = set_media_profile(profile);
        if (ret != HI_SUCCESS) {
            osal_printk("set media profile %d error:%d.\n", profile, ret);
            pm_ctrl(1);
            return HI_FAILURE;
        }
        pm_ctrl(1);
        set_media_freq_reg(&media_freq);
        memcpy(&s_media_freq, &media_freq, sizeof(hi_media_freq));
        s_bset_media_freq_done = HI_TRUE;
    } else { /** reduce the frequency first, then reduction voltage */
        set_media_freq_reg(&media_freq);
        memcpy(&s_media_freq, &media_freq, sizeof(hi_media_freq));
        s_bset_media_freq_done = HI_TRUE;
        pm_ctrl(0);
        ret = set_media_profile(profile);
        if (ret != HI_SUCCESS) {
            osal_printk("set media profile %d error:%d.\n", profile, ret);
            pm_ctrl(1);
            return HI_FAILURE;
        }
        pm_ctrl(1);
    }
    set_media_usrcfg(usr_param);
    s_old_profile = profile;
    return HI_SUCCESS;
}

hi_s32 set_single_freq_by_usr_cfg(hi_mpi_pm_sigle_media_cfg *single_mod_param)
{
    /** depend on core domain**/
    hi_s32 ret = HI_SUCCESS;
#ifdef PM_DOMAIN_CORE_ON
    hi_mpi_pm_media_cfg media_usrcfg;
    if (single_mod_param == NULL) {
        osal_printk("error: single_mod_param is null!\n");
        return HI_FAILURE;
    }
    if (g_pm_dev.domain_num == 0) {
        osal_printk("error: no domain register!\n");
        return HI_FAILURE;
    }
    osal_memset(&media_usrcfg, 0, sizeof(hi_mpi_pm_media_cfg));
    switch (single_mod_param->mode) {
        case HI_PM_MEDIA_VI:
        case HI_PM_MEDIA_PIPEBE:
            osal_memcpy(&media_usrcfg.vi_cfg, &single_mod_param->un_media_cfg.vi_cfg, sizeof(hi_mpi_pm_media_vi_cfg));
            break;
        case HI_PM_MEDIA_VPSS:
        case HI_PM_MEDIA_VEDU:
        case HI_PM_MEDIA_VDEC:
        case HI_PM_MEDIA_AVSP:
        default:
            osal_printk("module is err\n");
            return HI_ERR_PM_ILLEGAL_PARAM;
    }

#endif
    return ret;
}

/*
 * set_media_voltage: set media domain voltage
 * parameter:set_volt(u_v)
 * return:0:ok;   -1:fail
 */
int set_media_voltage(int set_volt)
{
    if (g_pm_dev.domain_num == 0) {
        osal_printk("error: no domain register!\n");
        return -1;
    }
    if (g_pm_dev.pm_enable) {
        osal_printk("ERROR:please disable pm!\n");
        return -1;
    }
    if (media_domain_setvoltage(set_volt)) {
        return -1;
    }
    return 0;
}

#endif



